
/**		
 * 
 *	uk.co.lmfm.guppy.model.SVNProxy
 *	
 *	@version 1.00 | Jan 7, 2010
 *	@author Justin Windle
 *  
 **/
 
package uk.co.lmfm.guppy.model 
{
	import flash.errors.IOError;

	import uk.co.lmfm.util.StringUtil;
	import uk.co.lmfm.net.subversion.events.SVNClientErrorEvent;

	import flash.utils.ByteArray;

	import uk.co.lmfm.net.loading.QueueLoaderItem;

	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.filesystem.File;

	import uk.co.lmfm.net.loading.events.QueueLoaderEvent;
	import uk.co.lmfm.net.subversion.vo.SVNLogReportVO;
	import uk.co.lmfm.net.loading.QueueLoader;
	import uk.co.lmfm.guppy.application.enum.ApplicationConstants;
	import uk.co.lmfm.net.subversion.SVNClient;
	import uk.co.lmfm.net.subversion.events.SVNClientEvent;

	import org.osflash.thunderbolt.Logger;
	import org.puremvc.as3.multicore.interfaces.IProxy;
	import org.puremvc.as3.multicore.patterns.proxy.Proxy;

	/**
	 * SVNProxy
	 */
	public class SVNProxy extends Proxy implements IProxy 
	{
		//	----------------------------------------------------------------
		//	CONSTANTS
		//	----------------------------------------------------------------

		public static const NAME : String = "SVNProxy";

		//private static const REPOSITORY_URL : String = "http://papervision3d.googlecode.com/svn/trunk/";		//private static const REPOSITORY_URL : String = "http://lean-mean-fighting-machine-as3-library.googlecode.com/svn/";		private static const REPOSITORY_URL : String = "http://guppy-fdt-tool.googlecode.com/svn/";		private static const REPOSITORY_PATH : String = "/trunk/library/";

		//	----------------------------------------------------------------
		//	PRIVATE MEMBERS
		//	----------------------------------------------------------------

		private var _client : SVNClient = new SVNClient();
		private var _downloader : QueueLoader = new QueueLoader();
		private var _logReport : SVNLogReportVO;
		private var _lastProgress : Number;		private var _progress : Number;
		private var _completed : int;
		private var _numItems : int;

		//	----------------------------------------------------------------
		//	CONSTRUCTOR
		//	----------------------------------------------------------------

		public function SVNProxy(data : Object = null)
		{
			super(NAME, data);
			
			_downloader.addEventListener(QueueLoaderEvent.QUEUE_STARTED, onQueueStarted);
			_downloader.addEventListener(QueueLoaderEvent.QUEUE_COMPLETE, onQueueComplete);
			
			_downloader.addEventListener(QueueLoaderEvent.ITEM_STARTED, onItemStarted);			_downloader.addEventListener(QueueLoaderEvent.ITEM_PROGRESS, onItemProgress);			_downloader.addEventListener(QueueLoaderEvent.ITEM_COMPLETE, onItemComplete);
			_downloader.addEventListener(QueueLoaderEvent.ITEM_ERROR, onItemError);
		}

		//	----------------------------------------------------------------
		//	PUBLIC METHODS
		//	----------------------------------------------------------------

		override public function onRegister() : void
		{
			super.onRegister();
			
			_client.addEventListener(SVNClientEvent.CONNECTED, onClientConnected);			_client.addEventListener(SVNClientEvent.LOG_REPORT_RECIEVED, onLogReportRecieved);
			_client.addEventListener(SVNClientEvent.GOT_LATEST_REVISION_NUMBER, onGotLatestRevisionNumber);
			_client.addEventListener(SVNClientErrorEvent.RESPONSE_PARSE_ERROR, onParseResponseError);
			_client.connect(StringUtil.stripSlashes(REPOSITORY_URL + REPOSITORY_PATH));
		}

		public function getLatestRevisionNumber() : void
		{
			_client.getLatestRevisionNumber();
		}

		public function checkForUpdates() : void
		{
			_client.getLatestRevisionNumber();
		}

		public function getRevisions(startRevision : int, endRevision : int) : void
		{
			Logger.info("Getting revisions. start:" + startRevision + ", end:" + endRevision);
			_client.getRevisions(startRevision, endRevision);
		}

		public function checkout(report : SVNLogReportVO, destination : String) : void
		{
			_logReport = report;
			_downloader.clear(true);
			
			_numItems = _completed = 0;
			_progress = _lastProgress = 0.0;
			
			var isFile : Boolean;
			var localPath : String;
			var remotePath : String;
			var repositoryPath : String;
			
			for (var i : int = 0;i < report.paths.length;i++) 
			{
				repositoryPath = report.paths[i];
				
				isFile = repositoryPath.match(/\.([^\.]+)$/) != null;				isFile = report.paths[i].attribute("node-kind").toString().toLowerCase() == "file";
				
				if(isFile)
				{
					remotePath = String(REPOSITORY_URL + report.paths[i]).replace(new RegExp("(?<!:)/+", "ig"), "/");
					localPath = String(destination + "/" + report.paths[i].substr(REPOSITORY_PATH.length)).replace(new RegExp("(?<!:)/+", "ig"), "/");
					//trace(localPath, report.paths[i].substr(REPOSITORY_PATH.length));

					_downloader.addItem(remotePath, QueueLoader.FILETYPE_BINARY, localPath, 1.0, false, false).extra = repositoryPath;
					_numItems++;
					
					//Logger.info("Item queued for download: " + remotePath);
				}
			}
			
			_downloader.start();
		}

		//	----------------------------------------------------------------
		//	EVENT HANDLERS
		//	----------------------------------------------------------------

		private function onClientConnected(event : SVNClientEvent) : void
		{
			//Logger.info('SVN Client Connected. At Revision ' + _client.latestRevisionNumber);
			//sendNotification(ApplicationConstants.GOT_REPOSITORY_LATEST_REVISION_NUMBER, _client.latestRevisionNumber);
		}

		private function onGotLatestRevisionNumber(event : SVNClientEvent) : void
		{
			//Logger.info('At Revision ' + _client.latestRevisionNumber);
			sendNotification(ApplicationConstants.GOT_REPOSITORY_LATEST_REVISION_NUMBER, _client.latestRevisionNumber);
		}

		private function onLogReportRecieved(event : SVNClientEvent) : void
		{
			//Logger.info("Updates available: " + event.data.paths.length);
			sendNotification(ApplicationConstants.SVN_LOG_REPORT_RECIEVED, event.data);
		}

		private function onQueueStarted(event : QueueLoaderEvent) : void
		{
			Logger.info("Download queue started...");
		}

		private function onItemStarted(event : QueueLoaderEvent) : void
		{
			//Logger.info("Item started:" + event.item.url);
			sendNotification(ApplicationConstants.CHECKOUT_ITEM_STARTED, event.item.extra);
		}

		private function onItemProgress(event : QueueLoaderEvent) : void
		{
			var itemProgress : Number = event.item.progress / _numItems;
			
			_progress += itemProgress - _lastProgress;
			_lastProgress = itemProgress;
			
			sendNotification(ApplicationConstants.CHECKOUT_ITEM_PROGRESS, event.item.progress);
			sendNotification(ApplicationConstants.CHECKOUT_PROGRESS, _progress);
		}

		private function onItemError(event : QueueLoaderEvent) : void
		{
			// TODO Item doesn't exist in repo anymore, so delete it locally
			Logger.error("Error downloading item:" + event.text);
			_numItems--;
		}

		private function onItemComplete(event : QueueLoaderEvent) : void
		{
			//Logger.info("Item complete:" + event.item.url);

			var item : QueueLoaderItem = event.item;
			var path : String = String(item.id);
			var file : File = new File();
			
			try
			{
				file = file.resolvePath(path);
				
				if(file.exists)
				{
					if(!file.isDirectory) file.deleteFile();
				}
				
				var stream : FileStream = new FileStream();
				var bytes : ByteArray = ByteArray(item.data);
				
				if(!file.parent.exists)
				{
					try
					{
						file.parent.createDirectory();
					}
					catch(error : IOError)
					{
						Logger.error("Cannot create directory: " + file.parent.nativePath + " >> " + error.message);
					}
				}
				
				if(!file.isDirectory)
				{
					try
					{
						stream.open(file, FileMode.WRITE);
						stream.writeBytes(bytes, 0, bytes.length);
						stream.close();
					
						//Logger.info("File downloaded successfuly: " + path);
						sendNotification(ApplicationConstants.CHECKOUT_ITEM_COMPLETE, event.item.extra);
					}
					catch(error : IOError)
					{
						
						Logger.error("Cannot save file: " + path + " >> " + error.message);
					}
				}
			}
			catch(error : ArgumentError)
			{
				Logger.error("Error saving file:" + error.message);
			}
			
			_completed++;
			_progress = _completed / _numItems;
			
			sendNotification(ApplicationConstants.CHECKOUT_PROGRESS, _progress);
		}

		private function onQueueComplete(event : QueueLoaderEvent) : void
		{
			Logger.info("Download queue complete!");
			sendNotification(ApplicationConstants.CHECKOUT_COMPLETE, _logReport);
		}

		private function onParseResponseError(event : SVNClientErrorEvent) : void
		{
			Logger.error("Error parsing response:" + event.text);
		}

		//	----------------------------------------------------------------
		//	PUBLIC ACCESSORS
		//	----------------------------------------------------------------

		public function get latestRevisionNumber() : int
		{
			return _client.latestRevisionNumber;
		}
	}
}
